#########################################################################
#			node_server.py : Server class that runs on the node			#
#																		#
#########################################################################

# Import Python modules
import threading
import log
import os, subprocess as sp,re
from SimpleXMLRPCServer import SimpleXMLRPCServer

# Import eChk modules
import vm
import ss
import nodeutils
import checkpointutils
import siglmutils

# Defines
DEFAULT_PORT = 9000

# XML RPC Server wrapper class
class StoppableSimpleXMLRPCServer(SimpleXMLRPCServer):
    
	def serve_forever(self):
		self.run = True
		self.socket.settimeout(1)
		while self.run:
			self.handle_request()

	def stop(self):
		self.run = False
		self.socket.close()

# Main RPC server object which runs on the node
class RPCServer(object):

	# Constructor
	def __init__(self):

		# Parse/set network vars
		self.port = DEFAULT_PORT
		self.host_sp = sp.Popen('echo $HOSTNAME',shell=True,stdout=sp.PIPE)
		self.hostname = re.sub("\s+",'',self.host_sp.communicate()[0])
		if 'csc.ncsu.edu' not in self.hostname:
			self.hostname += '.csc.ncsu.edu'
		log.write('Running from host ' + self.hostname)
		
		# Create the server
		self.server = StoppableSimpleXMLRPCServer((self.hostname, self.port))
		self.server_thread = None
		
		# Register RPC functions
		self.RegisterRPCFunctions()
		
	# Start the XML-RPC server as a new thread
	def start(self):
		log.write('Starting XML-RPC server.')

		#self.server_thread = threading.Thread( target = self.serve )
		#self.server_thread.start()
		self.serve()

	# Stop the server and its thread
	def stop(self):		
		self.server.stop()
		#self.server_thread.join()

	# Register the RPC
	def register_rpc(self, func):
		self.server.register_function(func)

	# Serve forever
	def serve(self):
		log.write("RPC server started on port %i" % self.port)
		self.server.serve_forever()
	
	# Register all RPC functions
	def RegisterRPCFunctions(self):
		self.register_rpc(self.EnumerateVMs)
		self.register_rpc(self.TakeSnapshot)
		self.register_rpc(self.Migrate)
		self.register_rpc(self.SetupSiglm)
		
	# Enumerate VMs running on this box
	def EnumerateVMs(self):
	
		# Enumerate domIDs
		domIDList = nodeutils.EnumVMDomIDs()
		
		# Build VM objects
		vmList = []
		for domID in domIDList:
			vmList.append(nodeutils.BuildVMObj(domID))			
		
		# Build list of pickled VMs (base64 encoded)
		pickledVMList = []
		for thisVM in vmList:
			pickledVMList.append(vm.PickleVM(thisVM))
		
		# Return
		return pickledVMList

	# Take a snapshot of a VM
	def TakeSnapshot(self, pickledTargetVM):
	
		# Unpickle the target VM
		targetVM = vm.UnPickleVM(pickledTargetVM)
		
		# Take the snapshot
		mySnapshot = checkpointutils.PerformSaveSnapshot(targetVM)
		
		# Pickle it
		pickledSnapshot = ss.PickleSnapshot(mySnapshot)
		
		# Return it
		return pickledSnapshot
	
	# Migrates the VM to the new PM
	def Migrate(self, pickledTargetVM):
	
		# Unpickle the target VM
		targetVM = vm.UnPickleVM(pickledTargetVM)
		
		# Migrate
		migrateSuccess = checkpointutils.Migrate(targetVM)
		
		# Return
		return migrateSuccess
	
	# Setup SigLM on PM
	def SetupSiglm(self):
		
		retVar = siglmutils.Setup()
		
		return retVar	
